﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.IO;
namespace NextCore
{
    public class CreateProgramError : Exception
    {
        public CreateProgramError()
            : base("Unable to create GLSL program.")
        {
        }
    }
    public class LinkError : Exception
    {
        public LinkError(string msg)
            : base("Glsl error link. Msg:"+msg)
        {
        }
    }
    public class CompileError : Exception
    {
        public CompileError(string msg)
            : base("Glsl error compile. Msg:" + msg)
        {
        }
       
    }
    public class Shader
    {
        public int Prog, VS=-1, FS=-1;
        public Shader(string vert, string frag = "")
        {
            Prog  = GL.CreateProgram();
            if (Prog < 1)
            {
                throw new CreateProgramError();
            }
            if (vert != "")
            {
                VS = GL.CreateShader(ShaderType.VertexShader);
                Compile(VS, vert);
            }
            if (frag != "")
            {
                FS = GL.CreateShader(ShaderType.FragmentShader);
                Compile(FS, frag);
            }
            if (VS > -1)
            {
                GL.AttachShader(Prog, VS);
            }
            if (FS > -1)
            {
                GL.AttachShader(Prog, FS);
            }
            GL.LinkProgram(Prog);

            int[] info = new int[32];
            GL.GetProgram(Prog, GetProgramParameterName.LinkStatus, info);
            if (info[0] == 0)
            {
                throw new LinkError(GL.GetProgramInfoLog(Prog));
            }

        }
        public void Compile(int id, string path)
        {
            string ss = "";
            try
            {
                ss = File.ReadAllText(path);
            }
            catch
            {
                throw new CompileError("File not found.");
            }
                GL.ShaderSource(id, ss);
            GL.CompileShader(id);
            string il=GL.GetShaderInfoLog(id);
            int[] info = new int[32];
            GL.GetShader(id,ShaderParameter.CompileStatus, info);
            if (info[0] == 0)
            {
                throw new CompileError(il);
            }
        }
        public void Use()
        {
            GL.UseProgram(Prog);
        }
        public void Release()
        {
            GL.UseProgram(0);
        }
        public int GetUni(string id)
        {
            return GL.GetUniformLocation(Prog, id);
        }
        public int GetAtt(string id)
        {
            return GL.GetAttribLocation(Prog, id);
        }
        public void SetInt(string id, int v)
        {
            GL.Uniform1(GetUni(id), v);
        }
        public void SetInt2(string id, int v1, int v2)
        {
            GL.Uniform2(GetUni(id),v1,v2);
        }
        public void SetInt3(string id, int v1, int v2, int v3)
        {
            GL.Uniform3(GetUni(id), v1, v2, v3);
        }
        public void SetInt4(string id, int v1, int v2, int v3, int v4)
        {
            GL.Uniform4(GetUni(id), v1, v2, v3, v4);
        }
        public void SetBool(string id, bool s)
        {
            GL.Uniform1(GetUni(id), s == true ? 0 : 1);
        }
            
        public void SetFloat(string id, float v)
        {
            GL.Uniform1(GetUni(id), v);
        }
        public void SetVec2(string id, Vector2 v)
        {
            GL.Uniform2(GetUni(id), v);
         }
        public void SetVec3(string id, Vector3 v)
        {
            GL.Uniform3(GetUni(id), v);
        }
        public void SetVec4(string id, Vector4 v)
        {
            GL.Uniform4(GetUni(id), v);
        }
        public void SetMat4(string id, Matrix4 m)
        {
            GL.UniformMatrix4(GetUni(id),false, ref m);
        }
    }
}
